package de.hwrBerlin.dataMining.view;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;

import org.dom4j.Document;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ScrollBar;

import de.hwrBerlin.dataMining.constants.ConfigConstants;
import de.hwrBerlin.dataMining.constants.Images;
import de.hwrBerlin.dataMining.dataStructure.DecisionTreeNode;
import de.hwrBerlin.dataMining.dataStructure.TableData;
import de.hwrBerlin.dataMining.dataStructure.TreeNode;
import de.hwrBerlin.dataMining.view.vImage.VImage;

public class TreePainter extends ScrolledComposite {

    private double _zoomFactor = 1;

	private TreeNode _root;
	private TreeNode _selectedNode;
    private Image _key_open = new Image(null, Images.KEY_OPEN);
    private Image _key_close = new Image(null, Images.KEY_CLOSE);
    private Image _key_icon;
    private Image _key = new Image(null, Images.KEY);
    private boolean _isKeyVisible = false;
	private final int _border = 10;
	private final int _attributeHeigh = 80;
	private final int _spaceHeigh = 60;
	private final int _spaceWidth = 10;

    private final int _fontHeight = 10;
    private final int _fontSpace = 4;

	private Color _background;
	private Color _nodeBackground;
	private Color _nodeForeground;
	private Color _leafBackground;
	private Color _leafForeground;
	private Color _selectedNodeBackground;
	private Color _selectedForeground;
	
	private Map<Rectangle, TreeNode> _nodeCoordinates = new HashMap<Rectangle, TreeNode>();
    private Composite _paintComposite;

    private List<TreeNode> _painted = new ArrayList<TreeNode>();

    // 0 = normal
    // 1 = mit Mitteltaste navigieren
    // 2 = Navigation mit linker Maustaste wird vorbereitet
    // 3 = mit linker Taste navigieren
    private int _mouseMode = 0;
    ArrayList<Integer> _freeModi = new ArrayList<Integer>();
    private Point _mouseMoveModeCenter = new Point(0, 0);
    private int _mouseMoveModeXDirection = 0;
    private int _mouseMoveModeYDirection = 0;
    private Timer _mouseMoveModeTimer;

	public TreePainter(final Composite pParent, int pStyle, final TreeView pTreeView) {
		super(pParent, pStyle);

        _freeModi.add(0);
        _freeModi.add(2);
        
		setColors();
		this.setBackground(_background);
		
        if(_isKeyVisible){
            _key_icon = _key_close;
        }
        else{
            _key_icon = _key_open;
        }
		
		_paintComposite = new Composite(this, SWT.NONE);
		_paintComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		_paintComposite.addPaintListener(new PaintListener() {

			@Override
			public void paintControl(PaintEvent pE) {
			    VImage image = new VImage(null, getMaxTreeSize().x, getMaxTreeSize().y);
			    
			    // Baum zeichnet
			    paintTree(image);
			    image.paintImage(pE.gc);
			    
			    // Legende zeichnen
	            if(_isKeyVisible){
	                pE.gc.drawImage(_key, 0, 0);
	            }
                pE.gc.drawImage(_key_icon, 0, 0);
			}

		});
		
		addMouseListener(new MouseAdapter() {

            @Override
            public void mouseUp(MouseEvent pE) {
                
                if(pE.button == 1 && _freeModi.contains(_mouseMode)){
                    if(_key_icon.getBounds().contains(pE.x, pE.y)){
                        
                        _isKeyVisible = !_isKeyVisible;
                        
                        if(_isKeyVisible){
                            _key_icon = _key_close;
                        }
                        else{
                            _key_icon = _key_open;
                        }
                        
                        repaint(_root);
                    }
                    
                    if(!_key_icon.getBounds().contains(pE.x, pE.y) && !(_isKeyVisible && _key.getBounds().contains(pE.x, pE.y))){
                        DecisionTreeNode foundNode = (DecisionTreeNode) findNodeAtPosition(pE.x, pE.y);
                        if (foundNode != _selectedNode && pTreeView != null) {
                            pTreeView.selectNode(foundNode);
                            _selectedNode = foundNode;
                            repaint(_root);
                        }
                    }
                }
                else if(pE.button == 2 && _freeModi.contains(_mouseMode)){
                    
                    MouseMoveListener mouseMoveListener = new MouseMoveListener() {

                        private int calculateMouseMoveModeDirection(double newPosition, double oldPosition){
                            return (int) ((newPosition - oldPosition) / 2 / 5 * 5);
                        }
                        
                        @Override
                        public void mouseMove(MouseEvent pE) {
                            int xPos = pE.x - getHorizontalBar().getSelection();
                            int yPos = pE.y - getVerticalBar().getSelection();
                            _mouseMoveModeXDirection = calculateMouseMoveModeDirection(xPos, _mouseMoveModeCenter.x);
                            _mouseMoveModeYDirection = calculateMouseMoveModeDirection(yPos, _mouseMoveModeCenter.y);
                            
                            if(_mouseMoveModeXDirection < 0){
                                if(_mouseMoveModeYDirection < 0){
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZENW), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZENW));
                                }
                                else if(_mouseMoveModeYDirection > 0){
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZESW), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZESW));
                                }
                                else{
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZEW), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZEW));
                                }
                            }
                            else if(_mouseMoveModeXDirection > 0){
                                if(_mouseMoveModeYDirection < 0){
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZENE), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZENE));
                                }
                                else if(_mouseMoveModeYDirection > 0){
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZESE), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZESE));
                                }
                                else{
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZEE), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZEE));
                                }
                            }
                            else{
                                if(_mouseMoveModeYDirection < 0){
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZEN), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZEN));
                                }
                                else if(_mouseMoveModeYDirection > 0){
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZES), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZES));
                                }
                                else{
                                    getCursor().dispose();
                                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZEALL), 16, 16));
//                                    setCursor(new Cursor(getDisplay(), SWT.CURSOR_SIZEALL));
                                }
                            }
                        }
                    };
                    MouseListener mouseListener = new MouseAdapter() {
                        
                        @Override
                        public void mouseUp(MouseEvent pE) {
                            if(_mouseMode != 0){
                                getCursor().dispose();
                                setCursor(new Cursor(null, SWT.CURSOR_ARROW));
                                _mouseMoveModeTimer.cancel();
                                _mouseMode = 0;
                            }
                        }
                    };
                    
                    addMouseMoveListener(mouseMoveListener);
                    addMouseListener(mouseListener);
                    
                    _mouseMode = 1;
                    _mouseMoveModeCenter.x = pE.x - getHorizontalBar().getSelection();
                    _mouseMoveModeCenter.y = pE.y - getVerticalBar().getSelection();
//                    getCursor().dispose();
                    setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_SIZEALL), 16, 16));
//                    setCursor(new Cursor(null, SWT.CURSOR_SIZEALL));
                    _mouseMoveModeTimer = new Timer();
                    _mouseMoveModeTimer.schedule(new TimerTask() {
                        
                        @Override
                        public void run() {
                            if(!isDisposed()){
                                getDisplay().asyncExec(new Runnable() {
                                    public void run() {
                                        scroll(_mouseMoveModeXDirection, _mouseMoveModeYDirection);
                                    }
                                });
                            }
                        }
                    }, 0, 50);
                    
                    while (_mouseMode == 1) {
                        if(!isDisposed()){
                            Display display = getDisplay();
                            if(!display.readAndDispatch()){
                                display.sleep();
                            }
                        }
                    }
                    
                    removeMouseMoveListener(mouseMoveListener);
                    removeMouseListener(mouseListener);
                }
            }
            
            @Override
            public void mouseDown(MouseEvent pE) {
                
                setFocus();
                
                if(pE.button == 1 && _freeModi.contains(_mouseMode)){
                    
                    MouseMoveListener mouseMoveListener = new MouseMoveListener() {
                        
                        @Override
                        public void mouseMove(MouseEvent pE) {
                            
                            if(_mouseMode != 3){
                                _mouseMode = 3;
//                                getCursor().dispose();
                                setCursor(new Cursor(getDisplay(), new ImageData(Images.CURSOR_GRABBER), 16, 16));
//                                setCursor(new Cursor(null, SWT.CURSOR_SIZEALL));
                            }
                            
                            _mouseMoveModeXDirection = _mouseMoveModeCenter.x - pE.x;
                            _mouseMoveModeYDirection = _mouseMoveModeCenter.y - pE.y;
                            scroll(_mouseMoveModeXDirection, _mouseMoveModeYDirection);
                        }
                    };
                    
                    MouseListener mouseListener = new MouseAdapter() {
                        
                        @Override
                        public void mouseUp(MouseEvent pE) {
                            if(_mouseMode != 0 && pE.button == 1){
                                if(_mouseMode == 3){
                                    getCursor().dispose();
                                }
                                setCursor(new Cursor(null, SWT.CURSOR_ARROW));
                                _mouseMode = 0;
                            }
                        }
                    };
                    
                    addMouseMoveListener(mouseMoveListener);
                    addMouseListener(mouseListener);

                    _mouseMode = 2;
                    _mouseMoveModeCenter.x = pE.x;
                    _mouseMoveModeCenter.y = pE.y;
                    
                    while (_mouseMode == 2 || _mouseMode == 3) {
                        if(!isDisposed()){
                            Display display = getDisplay();
                            if(!display.readAndDispatch()){
                                display.sleep();
                            }
                        }
                    }
                    
                    removeMouseMoveListener(mouseMoveListener);
                    removeMouseListener(mouseListener);
                }
            }

            private TreeNode findNodeAtPosition(int pX, int pY) {
                for (Rectangle rectangle : _nodeCoordinates.keySet()) {
                    if (rectangle.contains(pX, pY)) {
                        return _nodeCoordinates.get(rectangle);
                    }
                }

                return null;
            }
        });
		
		setFocus();
	}
	
	@Override
	public void addMouseListener(MouseListener pListener) {
	    super.addMouseListener(pListener);
	    _paintComposite.addMouseListener(pListener);
	}
	
	@Override
	public void removeMouseListener(MouseListener pListener) {
	    super.removeMouseListener(pListener);
        _paintComposite.removeMouseListener(pListener);
	}
    
	@Override
	public void addMouseMoveListener(MouseMoveListener pListener) {
	    super.addMouseMoveListener(pListener);
	    _paintComposite.addMouseMoveListener(pListener);
	}
	
	@Override
	public void removeMouseMoveListener(MouseMoveListener pListener) {
	    super.removeMouseMoveListener(pListener);
	    _paintComposite.removeMouseMoveListener(pListener);
	}
	
	@Override
	public void addMouseWheelListener(MouseWheelListener pListener) {
	    super.addMouseWheelListener(pListener);
	    _paintComposite.addMouseWheelListener(pListener);
	}
	
	@Override
	public void removeMouseWheelListener(MouseWheelListener pListener) {
	    super.removeMouseWheelListener(pListener);
	    _paintComposite.removeMouseWheelListener(pListener);
	}
	
    private void scroll(int pX, int pY){
        ScrollBar horizontalBar = getHorizontalBar();
        ScrollBar verticalBar = getVerticalBar();
        int x = horizontalBar.getSelection() + pX;
        int y = verticalBar.getSelection() + pY;

        x = (x < horizontalBar.getMinimum()) ? horizontalBar.getMinimum() : x;
        x = (x > horizontalBar.getMaximum()) ? horizontalBar.getMaximum() : x;
        y = (y < verticalBar.getMinimum()) ? verticalBar.getMinimum() : y;
        y = (y > verticalBar.getMaximum()) ? verticalBar.getMaximum() : y;

        setOrigin(x, y);
    }
    
    private void paintTree(VImage pImage) {

        _nodeCoordinates.clear();
        _paintComposite.setBackground(_background);
        TreePainter.this.setBackground(_background);
        pImage.setBackground(_background);
        pImage.setForeground(_background);
        pImage.drawRectangle(0, 0, getMaxTreeSize().x, getMaxTreeSize().y);

        if (_root != null) {

            _painted = new ArrayList<TreeNode>();
            pImage.setFontName("Courier");
            pImage.setFontSize(zoomSize(_fontHeight));

            int width = _border;
            Stack<DecisionTreeNode> toPaint = new Stack<DecisionTreeNode>();
            for (TreeNode treeNode : _root.getAllLeafs()) {
                toPaint.push((DecisionTreeNode)treeNode);
            }
            Stack<Point> pointsForLines = new Stack<Point>();
            while (!toPaint.isEmpty()) {
                DecisionTreeNode paintingNode = toPaint.pop();
                int nodeWidth = getNodeWidth(paintingNode);
                int xPos = width;
                int yPos = _border + (_spaceHeigh + _attributeHeigh) * (paintingNode.getElementDepth() - 1);
                int childSize = 0;
                for (TreeNode item : paintingNode.getAllLeafs()) {
                    childSize += getNodeWidth((DecisionTreeNode)item);
                    childSize += _spaceWidth;
                }
                childSize -= _spaceWidth;
                xPos -= childSize / 2;
                if (!paintingNode.isLeaf()) {
                    xPos -= (nodeWidth / 2);
                    xPos -= _spaceWidth / 2;
                } else {
                    xPos += (nodeWidth / 2);
                    xPos += _spaceWidth / 2;
                }

                pImage.setAntialias(SWT.ON);
                for (String key : paintingNode.getChilds().keySet()) {
                    int xStartLine = xPos + nodeWidth / 2;
                    int yStartLine = yPos + _attributeHeigh / 2;
                    int xEndLine = pointsForLines.peek().x;
                    int yEndLine = pointsForLines.pop().y;
                    int xText = xEndLine - (getStringPixelSize(key) / 2);
                    int yText = yEndLine - _fontHeight - (2 *_fontSpace);
                    pImage.setForeground(_nodeForeground);
                    pImage.setBackground(_background);
                    pImage.setLineWidth(zoomSize(1));
                    pImage.drawLine(zoomSize(xStartLine), zoomSize(yStartLine), zoomSize(xEndLine), zoomSize(yEndLine));
                    if (_zoomFactor > 0.3) {    
                        pImage.drawText(key, zoomSize(xText), zoomSize(yText));
                    }
                }
                if (_zoomFactor > 0.3 && !paintingNode.isLeaf()) {
                    DecimalFormat format = new DecimalFormat("0.00");
                    String weightedEntropyText = format.format(paintingNode.calculateWeightedEntropy()) + "";
                    int xText = xPos + nodeWidth / 2 - (getStringPixelSize(weightedEntropyText) / 2);
                    int yText = yPos + _attributeHeigh + (2 *_fontSpace);
                    pImage.drawText(weightedEntropyText, zoomSize(xText), zoomSize(yText));
                }
                paintNodeAtPosition(paintingNode, xPos, yPos, pImage);

                _painted.add(paintingNode);
                pointsForLines.push(new Point(xPos + nodeWidth / 2, yPos));

                if (paintingNode.getChilds().size() == 0) {
                    width += nodeWidth;
                    width += _spaceWidth;
                }
                if (paintingNode.getParent() != null && allChildsPainted(paintingNode.getParent())) {
                    toPaint.push((DecisionTreeNode) paintingNode.getParent());
                    continue;
                }
            }
            
        }
        
    }

    private boolean allChildsPainted(TreeNode pParent) {
        for (String itemKey : pParent.getChilds().keySet()) {
            if (!_painted.contains(pParent.getChilds().get(itemKey))) {
                return false;
            }
        }
        return true;
    }
    
    private int getNodeWidth(DecisionTreeNode pNode){
        int width = 0;
        
        for (Object line : getNodeStrings(pNode)) {
            width = Math.max(width, ((String)line).length());
        }

        width = (int) (getStringPixelSize(width) + 2 * 40);
        
        return width;
    }
    
    private Object[] getNodeStrings(DecisionTreeNode pNode){
        ArrayList<String> list = new ArrayList<String>();
        
        DecimalFormat format = new DecimalFormat("0.00");

        list.add(pNode.getCountOfElements() + "");
        list.add(pNode.getNodeName());
        list.add(format.format(pNode.calculateEntropy()) + "");

        if(pNode.isLeaf()){
            list.add("-----");
            
            TableData table = pNode.getSourceTable();
            int elementCount = table.getRowCount() - 1;
            Map<String, Integer> valueCounts = table.getValueCountsForAttributName(pNode.getTargetAttribute());
            for (String value : valueCounts.keySet()) {
                list.add(value + ": " + valueCounts.get(value) + " / " + elementCount);
            }
        }
        return list.toArray();
    }
    
    
    private int getNodeHeight(DecisionTreeNode pNode){
        int height = _attributeHeigh;
        if(pNode.isLeaf()){
            height += getLeafPlusHeight(pNode);
        }
        return height;
    }
    
    private int getLeafPlusHeight(DecisionTreeNode pNode){
        return (pNode.getSourceTable().getCountOfDifferentValuesFromAttributName(pNode.getTargetAttribute()) + 1) * (_fontHeight + _fontSpace);
    }

    private void paintNodeAtPosition(DecisionTreeNode pNode, int pX, int pY, VImage pImage) {
        int nodeWidth = getNodeWidth(pNode);
        int nodeHeight = getNodeHeight(pNode);

        _nodeCoordinates.put(new Rectangle(zoomSize(pX), zoomSize(pY), zoomSize(nodeWidth), zoomSize(nodeHeight)), pNode);
        if (pNode != _selectedNode) {
            if (pNode.isLeaf()) {
                pImage.setBackground(_leafBackground);
                pImage.setForeground(_leafForeground);
            }
            else{
                pImage.setBackground(_nodeBackground);
                pImage.setForeground(_nodeForeground);
            }
        } else {
            pImage.setBackground(_selectedNodeBackground);
            pImage.setForeground(_selectedForeground);
        }
        pImage.setLineWidth(zoomSize(2));

        if (pNode.isLeaf()) {
            pImage.drawRectangle(zoomSize(pX), zoomSize(pY), zoomSize(nodeWidth), zoomSize(nodeHeight));
        } else {
            pImage.drawOval(zoomSize(pX), zoomSize(pY), zoomSize(nodeWidth), zoomSize(nodeHeight));
        }

        if (_zoomFactor > 0.3) {
            int textY = (int) (pY + _attributeHeigh/2 - _fontHeight/2 - _fontSpace - _fontHeight);
            
            for (Object value : getNodeStrings(pNode)) {
                
                String writeString = (String)value;
                pImage.drawText(writeString, zoomSize(pX + (nodeWidth - getStringPixelSize(writeString)) / 2), zoomSize(textY));
                textY += _fontHeight + _fontSpace;
            }
        }
    }
    
    
    public Image toImage(){
        
        VImage image = new VImage(null, getMaxTreeSize().x, getMaxTreeSize().y);
        paintTree(image);
        
        return image.toImage();
        
    }
    
    
    public Document toSVG(){
        
        VImage image = new VImage(null, getMaxTreeSize().x, getMaxTreeSize().y);
        paintTree(image);
        
        return image.toSVG();
        
    }
	
	private void setColors(){
        _background = new Color(getDisplay(), ConfigConstants.TREE_BACKGROUND_COLOR);
        _nodeBackground = new Color(getDisplay(), ConfigConstants.TREE_NODE_BACKGROUND_COLOR);
        _nodeForeground = new Color(getDisplay(), ConfigConstants.TREE_NODE_FOREGROUND_COLOR);
        _leafBackground = new Color(getDisplay(), ConfigConstants.TREE_LEAF_BACKGROUND_COLOR);
        _leafForeground = new Color(getDisplay(), ConfigConstants.TREE_LEAF_FOREGROUND_COLOR);
        _selectedNodeBackground = new Color(getDisplay(), ConfigConstants.TREE_SELECTED_BACKGROUND_COLOR);
        _selectedForeground = new Color(getDisplay(), ConfigConstants.TREE_SELECTED_FOREGROUND_COLOR);
	}
    
    private int zoomSize(double pSize){
        return (int)(pSize*_zoomFactor);
    }

    /**
     * Zoomt den Baum
     * 
     * @param pSelection
     */
    public void zoom(int pSelection) {
        _zoomFactor = (double) (100 - pSelection) / (double) 50;
        if (_zoomFactor == 0) {
            _zoomFactor = 0.01;
        }
        if (pSelection < 50) {
            _zoomFactor = _zoomFactor * _zoomFactor * _zoomFactor * _zoomFactor;
        }
        repaint(_root);
    }

    private int getStringPixelSize(String pString) {
        return getStringPixelSize(pString.length());
    }

    private int getStringPixelSize(int pLength) {
        return pLength * 8;
    }
	
	private Point getMaxTreeSize(){
	    int x = _border * 2;
	    int y = _border * 2 + _attributeHeigh * _root.getTreeDepth() + _spaceHeigh * (_root.getTreeDepth() - 1);
	    
	    int plusY = 0;
	    for (TreeNode leaf : _root.getAllLeafs()) {
	        plusY = Math.max(plusY, getLeafPlusHeight((DecisionTreeNode)leaf));
        }
	    y += plusY;

        for (TreeNode treeNode : _root.getAllLeafs()) {
            x += getNodeWidth((DecisionTreeNode) treeNode);
        }
        x += _spaceWidth * (_root.getAllLeafs().size());

        x = zoomSize(x);
        y = zoomSize(y);
        
        return new Point(x, y);
	}

	public void repaint(TreeNode pRoot) {
	    setColors();
        this.setBackground(_background);
		_root = pRoot;
		if (_root != null) {
			Point origin = getOrigin();
			int maxWidth = getMaxTreeSize().x;
			int maxHeigh = getMaxTreeSize().y;
			setContent(_paintComposite);
            if(maxWidth < _key_icon.getBounds().x + _key_icon.getBounds().width){
                maxWidth = _key_icon.getBounds().x + _key_icon.getBounds().width;
            }
            if(maxHeigh < _key_icon.getBounds().y + _key_icon.getBounds().height){
                maxHeigh = _key_icon.getBounds().y + _key_icon.getBounds().height;
            }
            if(_isKeyVisible){
                if(maxWidth < _key.getBounds().x + _key.getBounds().width){
                    maxWidth = _key.getBounds().x + _key.getBounds().width;
                }
                if(maxHeigh < _key.getBounds().y + _key.getBounds().height){
                    maxHeigh = _key.getBounds().y + _key.getBounds().height;
                }
            }
			_paintComposite.setSize(maxWidth, maxHeigh);
			_paintComposite.redraw();
			setOrigin(origin);
		}
	}

	public TreeNode getTree() {
		return _root;
	}

	public void setSelection(TreeNode node) {
		_selectedNode = node;
	}

	public TreeNode getSelection() {
		return _selectedNode;
	}
}
